home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / ROOMMAZE.ZIP / ROOMMAZE.C < prev    next >
C/C++ Source or Header  |  1993-10-18  |  14KB  |  424 lines

  1. /****************************************/
  2. /* ROOMMAZE.C                           */
  3. /* (C) Copyright 1993 David Bollinger   */
  4. /* send comments to CIS ID# 72510,3623  */
  5. /* compiled with Borland C++ 3.0        */
  6. /* command line: bcc -ms -v- roommaze.c */
  7. /****************************************/
  8.  
  9. #include <bios.h>
  10. #include <stdlib.h>
  11. #include <time.h>
  12. #include "roommaze.h"
  13.  
  14. #define AND        &&
  15. #define OR         ||
  16. #define NOT        !
  17. #define SCREENX    320     // screen x dimension
  18. #define SCREENY    200     // screen y dimension
  19. #define MAZEX      80      // maze x dimension
  20. #define MAZEY      80      // maze y dimension
  21. #define GRIDX      4       // how coarse are the x coordinates
  22. #define GRIDY      4       // how coarse are the y coordinates
  23.                            //   basically defines minimum width and height
  24.                            //   also helps align room boundaries
  25.                            //   4 seems to be a pretty good value
  26. #define NUMRECT    32      // how many rectangles to draw rooms with
  27. #define MAXFLOOR   8       // how many different colors of floor (2-15)
  28.  
  29. // maze objects, defined by the following weighting map:
  30. //              +---+
  31. //              | 1 |
  32. //          +---+---+---+
  33. //          | 2 |X,Y| 4 |
  34. //          +---+---+---+
  35. //              | 8 |
  36. //              +---+
  37. //
  38. #define FL         0       // unused, empty floor
  39. #define NE         1       // north end
  40. #define WE         2       // west end
  41. #define LR         3       // lower right
  42. #define EE         4       // east end
  43. #define LL         5       // lower left
  44. #define HO         6       // horizontal wall
  45. #define ST         7       // south T
  46. #define SE         8       // south end
  47. #define VE         9       // vertical wall
  48. #define UR         10      // upper right
  49. #define ET         11      // east T
  50. #define UL         12      // upper left
  51. #define WT         13      // west T
  52. #define NT         14      // north T
  53. #define CC         15      // central cross
  54. #define HD         16      // horizontal door
  55. #define VD         17      // vertical door
  56.  
  57. #define F1         18      // floor 1
  58. #define F2         19      // floor 2
  59. #define F3         20      // floor 3
  60. #define F4         21      // floor 4
  61. #define F5         22      // floor 5
  62. #define F6         23      // floor 6
  63. #define F7         24      // floor 7
  64. #define F8         25      // floor 8
  65. #define F9         26      // floor 9
  66. #define Fa         27      // floor 10
  67. #define Fb         28      // floor 11
  68. #define Fc         29      // floor 12
  69. #define Fd         30      // floor 13
  70. #define Fe         31      // floor 14
  71. #define Ff         32      // floor 15
  72.  
  73. /********************/
  74. /* global variables */
  75. /********************/
  76. char maze[MAZEY][MAZEX];
  77.  
  78. /***********************/
  79. /* function prototypes */
  80. /***********************/
  81. void MakeRooms(void);
  82. void ClarifyWalls(void);
  83. void MakeDoors(void);
  84. void TraceWallForDoorX(int sx, int sy);
  85. void TraceWallForDoorY(int sx, int sy);
  86. void SimplifyMaze(void);
  87. void SetVideoMode(int mode);
  88. void Rectangle(int x1, int y1, int x2, int y2, int c);
  89. void WriteMaze(int x, int y, char c);
  90. char ReadMaze(int x, int y);
  91. void CheckOrder(int *a, int *b);
  92.  
  93. /***************************************************************************/
  94. main()
  95.    {
  96.    randomize();
  97.    SetVideoMode(19);       // 320x200 256 color VGA graphics mode
  98.  
  99.    while(bioskey(1))       // chew up any keys waiting in buffer
  100.       bioskey(0);
  101.  
  102.                            // insert extra bioskey(0)'s to see each step
  103.  
  104.    MakeRooms();            // make some walled in rooms with rectangles
  105.    ClarifyWalls();         // calculate exact wall type for each wall
  106.    MakeDoors();            // find walls and insert doors
  107.                            // save array to file here (?)
  108.    SimplifyMaze();         // make it look nice on VGA
  109.  
  110.    bioskey(0);             // wait for a key
  111.    SetVideoMode(3);        // return to 80x25 text mode
  112.    return 0;
  113.    }
  114.  
  115. /***************************************************************************/
  116. /* MakeRooms creates a number of random outlined rectangles.  As   */
  117. /* MAXFLOOR is increased it is more likely that the current room   */
  118. /* color will not match any underlying room colors, thus there     */
  119. /* will be more isolated "island" rooms of simpler shape.  As      */
  120. /* MAXFLOOR is decreased the opposite is true, resulting in fewer  */
  121. /* distinct rooms but each room being more complex in shape.       */
  122. /* Note that while MAXFLOOR=1 will accomplish nothing, other       */
  123. /* small values (including 2) can still generate interesting mazes */
  124. /*******************************************************************/
  125. void MakeRooms(void)
  126.    {
  127.    int numrects, r, x1, y1, x2, y2, c;
  128.  
  129.    numrects = NUMRECT;
  130.  
  131.    /*****************************************************/
  132.    /* first, create a "base" floor over the entire maze */
  133.    /*****************************************************/
  134.    Rectangle(0,0,MAZEX-1,MAZEY-1, F1);
  135.  
  136.    for (r=numrects; r>0; r--)
  137.       {
  138.       x1 = random((int)(MAZEX/GRIDX)) * GRIDX;
  139.       y1 = random((int)(MAZEY/GRIDY)) * GRIDY;
  140.       x2 = x1 + random((int)(MAZEX/GRIDX)) * GRIDX;
  141.       y2 = y1 + random((int)(MAZEY/GRIDY)) * GRIDY;
  142.       if (x2 > MAZEX-1)
  143.          x2 = MAZEX-1;
  144.       if (y2 > MAZEY-1)
  145.          y2 = MAZEY-1;
  146.  
  147.       c = random(MAXFLOOR)+F1;
  148.  
  149.       Rectangle(x1, y1, x2, y2, c);
  150.       }
  151.    }
  152.  
  153. /***************************************************************************/
  154. /* ClarifyWalls identifies the exact wall type of each WALL object */
  155. /* by examining its neighbors.  See weighting map above for an     */
  156. /* explanation of the calculation of index.                        */
  157. /*******************************************************************/
  158. void ClarifyWalls(void)
  159.    {
  160.    register int x, y, index;
  161.  
  162.    for (y=0; y<MAZEY; y++)
  163.       for (x=0; x<MAZEX; x++)
  164.          {
  165.          /*********************************/
  166.          /* if this is floor then skip it */
  167.          /*********************************/
  168.          if (ReadMaze(x,y) >= F1 )
  169.             continue;
  170.  
  171.          /**********************************************************/
  172.          /* check if neighboring squares are numerically less than */
  173.          /* floor type 1, indicating some type of wall, if a wall  */
  174.          /* then it affects the index value based on its location  */
  175.          /**********************************************************/
  176.          index  = (ReadMaze(x, y-1) < F1) ? 1 : 0;
  177.          index += (ReadMaze(x-1, y) < F1) ? 2 : 0;
  178.          index += (ReadMaze(x+1, y) < F1) ? 4 : 0;
  179.          index += (ReadMaze(x, y+1) < F1) ? 8 : 0;
  180.  
  181.          WriteMaze(x, y, index);
  182.          }
  183.    }
  184.  
  185. /***************************************************************************/
  186. /* MakeDoors scans for vertical and horizontal walls and inserts         */
  187. /* a door at a random position along the length or width of the wall.    */
  188. /* This method generally creates more doors than necessary (certainly    */
  189. /* more than a human would place for the same map), but it does          */
  190. /* guarantee that all areas of the maze are accessable.  Alternatively,  */
  191. /* a flood-fill type recursive method could scan the rooms for bordering */
  192. /* rooms and only insert a single door for each unique neighboring room, */
  193. /* but I wanted to stay away from recursion for speed reasons            */
  194. /*************************************************************************/
  195. void MakeDoors(void)
  196.    {
  197.    register int x, y, here;
  198.  
  199.    for (y=1; y<MAZEY-1; y++)
  200.       for (x=1; x<MAZEX-1; x++)
  201.          {
  202.          here = ReadMaze(x, y);
  203.          if (here == HO)              // found a horizontal wall
  204.             TraceWallForDoorX(x, y);  //   try to make a horizontal door
  205.          if (here == VE)              // found a vertical wall
  206.             TraceWallForDoorY(x, y);  //   try to make a vertical door
  207.          }
  208.    }
  209.  
  210. /***************************************************************************/
  211. /* TraceWallForDoorX scans horizontally trying to identify a wall segment */
  212. /* if it finds one, it inserts a door randomly along its length           */
  213. /**************************************************************************/
  214. void TraceWallForDoorX(int sx, int sy)
  215.    {
  216.    register int inc, x1, x2;
  217.    char here;
  218.  
  219.    // scan to the left
  220.    inc = 1;
  221.    while(sx-inc > 0)
  222.       {
  223.       here = ReadMaze(sx-inc, sy);
  224.       if (here==HD)   // there is already a door on this wall
  225.          return;
  226.       if (here != HO) // came to the end of the wall
  227.          break;
  228.       inc++;
  229.       }
  230.    x1 = sx-inc+1;
  231.  
  232.    // scan to the right
  233.    inc = 1;
  234.    while (sx+inc < MAZEX-1)
  235.       {
  236.       here = ReadMaze(sx+inc, sy);
  237.       if (here==HD)   // there is already a door on this wall
  238.          return;
  239.       if (here != HO) // came to the end of the wall
  240.          break;
  241.       inc++;
  242.       }
  243.    x2 = sx+inc-1;
  244.  
  245.    if (x2-x1 > 1)
  246.       WriteMaze(random(x2-x1)+x1, sy, HD);
  247.    }
  248.  
  249. /***************************************************************************/
  250. /* TraceWallForDoorY scans vertically trying to identify a wall segment */
  251. /* if it finds one, it inserts a door randomly along its length         */
  252. /************************************************************************/
  253. void TraceWallForDoorY(int sx, int sy)
  254.    {
  255.    register int inc, y1, y2;
  256.    char here;
  257.  
  258.    // scan above
  259.    inc = 1;
  260.    while(sy-inc > 0)
  261.       {
  262.       here = ReadMaze(sx, sy-inc);
  263.       if (here==VD)   // there is already a door on this wall
  264.          return;
  265.       if (here != VE) // came to the end of the wall
  266.          break;
  267.       inc++;
  268.       }
  269.    y1 = sy-inc+1;
  270.  
  271.    // scan below
  272.    inc = 1;
  273.    while (sy+inc < MAZEY-1)
  274.       {
  275.       here = ReadMaze(sx, sy+inc);
  276.       if (here==VD)   // there is already a door on this wall
  277.          return;
  278.       if (here != VE) // came to the end of the wall
  279.          break;
  280.       inc++;
  281.       }
  282.    y2 = sy+inc-1;
  283.  
  284.    if (y2-y1 > 1)
  285.       WriteMaze(sx, random(y2-y1)+y1, VD);
  286.    }
  287.  
  288. /***************************************************************************/
  289. /* SimplifyMaze un-translates all of the various floor, wall and door   */
  290. /* objects into 3 simple floor, wall and door objects.  Makes it look   */
  291. /* nicer with this simple VGA display, but it may be better to leave it */
  292. /* complex for actual use in a game                                     */
  293. /************************************************************************/
  294. void SimplifyMaze(void)
  295.    {
  296.    register int x, y;
  297.  
  298.    for (y=0; y<MAZEY; y++)
  299.       for (x=0; x<MAZEX; x++)
  300.          switch(ReadMaze(x, y))
  301.             {
  302.             case FL : break;
  303.             case F1 :
  304.             case F2 :
  305.             case F3 :
  306.             case F4 :
  307.             case F5 :
  308.             case F6 :
  309.             case F7 :
  310.             case F8 :
  311.             case F9 :
  312.             case Fa :
  313.             case Fb :
  314.             case Fc :
  315.             case Fd :
  316.             case Fe :
  317.             case Ff : WriteMaze(x, y, FL); break;
  318.             case HD : break;
  319.             case VD : WriteMaze(x, y, HD); break;
  320.             case CC : break;
  321.             default : WriteMaze(x, y, CC); break;
  322.             }
  323.    }
  324.  
  325. /***************************************************************************/
  326. /* BIOS call to set video mode */
  327. /*******************************/
  328. void SetVideoMode(int mode)
  329.    {
  330.    asm   xor   ah, ah
  331.    asm   mov   al, byte ptr mode
  332.    asm   int   10h
  333.    }
  334.  
  335. /***************************************************************************/
  336. void Rectangle(int x1, int y1, int x2, int y2, int c)
  337.    {
  338.    int x, y;
  339.  
  340.    /********************************************/
  341.    /* verify that x2>=x1 and y2>=y1            */
  342.    /* not really needed as the code sits, but  */
  343.    /* best to be safe in case code is modified */
  344.    /********************************************/
  345.    CheckOrder(&x1, &x2);
  346.    CheckOrder(&y1, &y2);
  347.  
  348.    /*******************************************************/
  349.    /* draw interior of rectangle with desired floor color */
  350.    /*******************************************************/
  351.    for (y=y1+1; y<y2; y++)
  352.       for (x=x1+1; x<x2; x++)
  353.          WriteMaze(x, y, c);
  354.  
  355.    /*********************************************************/
  356.    /* now draw smart border - only draw border if existing  */
  357.    /* color is not the same as requested floor color - this */
  358.    /* allows the rectangles to overlap and create more      */
  359.    /* interesting shapes than simple rectangles             */
  360.    /*********************************************************/
  361.    for (x=x1; x<=x2; x++)
  362.       {
  363.       if (ReadMaze(x, y1) != c)
  364.          WriteMaze(x, y1, CC);
  365.       if (ReadMaze(x, y2) != c)
  366.          WriteMaze(x, y2, CC);
  367.       }
  368.  
  369.    for (y=y1; y<=y2; y++)
  370.       {
  371.       if (ReadMaze(x1, y) != c)
  372.          WriteMaze(x1, y, CC);
  373.       if (ReadMaze(x2, y) != c)
  374.          WriteMaze(x2, y, CC);
  375.       }
  376.    }
  377.  
  378. /***************************************************************************/
  379. void WriteMaze(int x, int y, char c)
  380.    {
  381.    if ((x>=0) AND (x<MAZEX) AND (y>=0) AND (y<MAZEY))
  382.       {
  383.       maze[y][x] = c;
  384.  
  385.       // optional putpixel routine for graphic output
  386.       asm   mov   ax, 0xa000
  387.       asm   mov   es, ax
  388.       asm   mov   bx, word ptr y
  389.       asm   shl   bx, 1
  390.       asm   mov   bx, word ptr ytable[bx]
  391.       asm   add   bx, word ptr x
  392.       asm   mov   ax, word ptr c
  393.       asm   mov   byte ptr es:[bx], al
  394.       }
  395.    // could return an error if needed
  396.    }
  397.  
  398. /***************************************************************************/
  399. char ReadMaze(int x, int y)
  400.    {
  401.    if ((x>=0) AND (x<MAZEX) AND (y>=0) AND (y<MAZEY))
  402.       return maze[y][x];
  403.    else
  404.       return F1;   // return floor if out of range
  405.                    // so that ClarifyWalls works properly
  406.    }
  407.  
  408. /***************************************************************************/
  409. void CheckOrder(int *a, int *b)
  410.    {
  411.    int temp;
  412.  
  413.    if (*a > *b)
  414.       {
  415.       temp = *a;
  416.       *a = *b;
  417.       *b = temp;
  418.       }
  419.    }
  420.  
  421. /***************************************************************************/
  422. /* end of roommaze.c */
  423.  
  424.